#include <iostream>
#include <fsck.hxx>
using namespace std;

class fsck64Statistics;

class Inomap {
public:
    ino_t maxInum;
};

struct NewFsck64Argp {
    fsck64Statistics*  statPtr;

    Inomap* _inodeMap;
};

class phaseInfo
{
public:
    fsck64Statistics *statsPtr;

    enum fsck64PhaseId phaseId;
    const char *phaseStr;

    void init(fsck64Statistics *stPtr, fsck64PhaseId id)
    {
    }

    phaseInfo()
    {
        init(NULL, PHASE_INVALID);
    }

    ~phaseInfo()
    {
    }

    void initPhase(ulong64 objects, ulong32 totalSubPhases) {}
    void startPhase(ulong64 objects=0, const char *infoStr=NULL) {}
    void endPhase(const char *infoStr) {}
    void skipPhase(const char *infoStr) {}
    void initSubPhase(ulong32 subPhaseId, ulong64 objects) {}
    void startSubPhase(ulong32 subPhaseId, const char *infoStr) {}
    void endSubPhase(ulong32 subPhaseId, const char *infoStr) {}
    void skipSubPhase(ulong32 subPhaseId, const char *infoStr) {}
    void updateProgress(ulong64 objects) {}
    int getProgressInPercent() {}
    int getCurrentStatus() {}

};

class fsck64Statistics {
    fsck64Statistics* next;
    phaseInfo phase[TOTAL_PHASES];
    fsck64PhaseId curPhase;

public:
    void initPhase(fsck64PhaseId phId, ulong32 totalSubphases = 0) {}
    void startPhase(fsck64PhaseId phId, ulong64 objects = 0, const char *infoStr = NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        FSTOOLS_assert(curPhase == PHASE_NONE || phase[curPhase].getCurrentStatus() == PHASE_DONE);
        curPhase = phId;
        phase[phId].startPhase(objects, infoStr);
    }
    void endPhase(fsck64PhaseId phId, const char *infoStr=NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].endPhase(infoStr);
    }
    void skipPhase(fsck64PhaseId phId, const char *infoStr=NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].skipPhase(infoStr);
    }
    void initSubPhase(fsck64PhaseId phId, ulong32 subPhaseId, ulong64 objects)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].initSubPhase(subPhaseId, objects);
    }
    void startSubPhase(fsck64PhaseId phId, ulong32 subPhase, const char *infoStr=NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].startSubPhase(subPhase, infoStr);
    }
    void endSubPhase(fsck64PhaseId phId, ulong32 subPhId, const char *infoStr=NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].endSubPhase(subPhId, infoStr);
    }
    void skipSubPhase(fsck64PhaseId phId, ulong32 subPhId, const char *infoStr=NULL)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].skipSubPhase(subPhId, infoStr);
    }

    void updateProgress(fsck64PhaseId phId, ulong64 objects)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        phase[phId].updateProgress(objects);
    }

    int getPhaseStatusInPercent(fsck64PhaseId phId)
    {
        FSTOOLS_assert(phId >= PHASE_START && phId < TOTAL_PHASES);
        return phase[phId].getProgressInPercent();
    }
};

class task {
public:
    task() {}
    ~task() {}

    virtual void run() {}
};

class project {
    task*       curTask;
public:
    project(int memberCount, const char* name) {}
    ~project() {}

    void  issueTask (task* t) {
        setTask(t);
    }

    void setTask(task* t) {
        curTask = t;
    }
};

class Fsck64_SB {

public:
    Fsck64_SB() {}
    Fsck64_SB(NewFsck64Argp* argp) {}
    ~Fsck64_SB() {}
};

class FsckTask : public task {
protected:
    NewFsck64Argp* newFsck;

public:
    FsckTask():task() {}
    FsckTask(NewFsck64Argp* nFsck):newFsck(nFsck) {}
    ~FsckTask() {}
    virtual ulong64   getTotalObjects() { FSTOOLS_assert(0); return 0; };
    virtual boolean_t hasSubPhase()     { return FALSE; }
    virtual ulong32   getSubPhaseNum()  { FSTOOLS_assert(0); return 0; }
    virtual ulong64   getFirstSubPhaseObjects() { FSTOOLS_assert(0); return 0; }

    virtual void issueFsckTask(project* proj, fsck64PhaseId phaseId, const char *strInfo) {
        if (hasSubPhase()) {
            newFsck->statPtr->initPhase(phaseId, getSubPhaseNum());
            newFsck->statPtr->initSubPhase(phaseId, 0, getFirstSubPhaseObjects());
            // first sub phase id is always 0
            newFsck->statPtr->startSubPhase(phaseId, 0);
        } else {
            newFsck->statPtr->startPhase(phaseId, getTotalObjects(), strInfo);
        }
        cout<<*strInfo<<endl;
        proj->issueTask(this);
        newFsck->statPtr->endPhase(phaseId, strInfo);
    }

};

class Pass1Process64Inodes : public FsckTask {
    Fsck64_SB* sbptr;
public:
    Pass1Process64Inodes() {}
    ~Pass1Process64Inodes() {}
    Pass1Process64Inodes(NewFsck64Argp* nfsck, Fsck64_SB* sptr):FsckTask(nfsck), sbptr(sptr) { }
    void run() {}
    ulong64 getTotalObjects() {
       newFsck->_inodeMap->maxInum; 
    }
};

class chkfs64 {
private:
    NewFsck64Argp *newFsck;
    Fsck64_SB *sbptr;
    project* crtproject;

    FsckTask* pass1SlicemapInstance;
    FsckTask* pass1ReservedBlksInstance;
    FsckTask* pass1ProcessInodesInstance;
    task* pass1ProcessVbmBmdPair;
    FsckTask* pass1ProcessVersionFiles;
    FsckTask* pass1BrowseSharedBMD;
    FsckTask* pass1Search64DupBlks;
    FsckTask* reformatIBSlicePhase;
    FsckTask* pass2TaskInstance;
    FsckTask* pass3TaskInstance;

    //PassDLRecovery* passDLRecovery;
public:
    chkfs64() {}
    chkfs64(NewFsck64Argp* newFsck, Fsck64_SB* sbptr):newFsck(newFsck), sbptr(sbptr) {}
    ~chkfs64() {}
    File_Status Init() {
        char nfscknm[20];
        int nthreads = 1, nfsckval = 0;
        sprintf(nfscknm, "fck%d", nfsckval++);
        crtproject = new project(nthreads, nfscknm);

    }

    File_Status SliceMapPhase() {
        cout<<"Slice Map Phase ..."<<endl;
    }

    File_Status ReservedBlockPhase() {
        cout<<"ReservedBlock Phase ..."<<endl;
    }

    File_Status InodePhase() {
        cout<<"Inode Phase..."<<endl;
        pass1ProcessInodesInstance = new Pass1Process64Inodes(newFsck, sbptr);
        pass1ProcessInodesInstance->issueFsckTask(crtproject, INODE_SCAN_PHASE, " Validate Inodes");
    }

    File_Status phase2() {
        cout<<"Phase2..."<<endl;
    }

    File_Status phase3() {
        cout<<"Phase3..."<<endl;
    }

    File_Status execute() {
        File_Status fstatus = TRUE;
    
        fstatus = Init();
        fstatus = SliceMapPhase();
        fstatus = ReservedBlockPhase();
        fstatus = InodePhase();
        fstatus = phase2();
        fstatus = phase3();

        return fstatus;
    }
    
};

class Pass1ProcessReservedBlks : public task {
    NewFsck64Argp* newFsck;
    Fsck64_SB* sbptr;

public:
    void run();
    Pass1ProcessReservedBlks(NewFsck64Argp* nfsck, Fsck64_SB* sptr)
    : task (), newFsck (nfsck), sbptr (sptr) { }
};

class Pass1ProcessInodes : public task {
    NewFsck64Argp* newFsck;
    Fsck64_SB* sbptr;

public:
    void run();
    Pass1ProcessInodes( NewFsck64Argp* nfsck, Fsck64_SB* sptr)
    : task (), newFsck (nfsck), sbptr (sptr) { }
};

class Pass2Task : public task {
    NewFsck64Argp* newFsck;
    Fsck64_SB* sbptr;
  public:
    void run();
    Pass2Task( NewFsck64Argp* nfsck, Fsck64_SB* sptr)
    : task (), newFsck (nfsck), sbptr (sptr) { }
};

class Pass3Task : public task {
    NewFsck64Argp* newFsck;
    Fsck64_SB* sbptr;
  public:
    void run();
    Pass3Task( NewFsck64Argp* nfsck, Fsck64_SB* sptr)
    : task (), newFsck (nfsck), sbptr (sptr) { }
};

boolean_t fsck64_checkfilesys(
                            NewFsck64Argp* newFsck,
                            Fsck64_SB* sbptr
                            ) {
    chkfs64 *checkFileSystem64 = new chkfs64(newFsck, sbptr);
    boolean_t fsck_status = checkFileSystem64->execute();
    return TRUE;
}


boolean_t doNewFsck64(
                    void* fsckArgp = NULL
                    ) {
    NewFsck64Argp* newFsck = (NewFsck64Argp*)fsckArgp;
    Fsck64_SB* sbptr= new Fsck64_SB(newFsck);

    boolean_t retval = fsck64_checkfilesys(newFsck, sbptr);
    return retval;

}

int main(void) {
    NewFsck64Argp *fsckArgp = new NewFsck64Argp();
    doNewFsck64(fsckArgp);
    cout<<"Hello"<<endl;
    return 1;
}
